﻿
Imports System.Net.Sockets
Imports System.Threading
Imports System.Net
Imports udpTrans

Public Class udpserver
    Public Event receive(ByVal handle As talkHandle)
    Public Const defaultPort As Int32 = 10000
    Public Shared ReadOnly defaultThreadCount As Int64 =
        ifoper(Environment.ProcessorCount() < 2, 2, Convert.ToInt64(Environment.ProcessorCount()))
    Public Const defaultWaitTime As Int64 = 1
    Public Const defaultHoldTime As Int64 = 30000
    Public holdtime As Int64 = defaultHoldTime
    Private threads() As Thread = Nothing
    Private _port As Int32 = 0

    Public Sub New(Optional ByVal port As Int32 = defaultPort)
        Me.New(port, defaultThreadCount)
    End Sub

    Public Sub New(ByVal port As Int32, ByVal threadCount As Int64)
        Me._port = port
        Me.threadCount = threadCount
    End Sub

    Public Property threadCount() As Int64
        Get
            assert(Not threads Is Nothing AndAlso threads.Length() > 0)
            Return threads.Length()
        End Get
        Set(ByVal value As Int64)
            assert(threads Is Nothing OrElse threads.Length() = 0)
            assert(value > 0)
            ReDim threads(value - 1)
        End Set
    End Property

    Public Property port() As Int32
        Get
            Return _port
        End Get
        Set(ByVal value As Int32)
            _port = value
        End Set
    End Property

    Public Sub start()
        For i As Int64 = 0 To threads.Length() - 1
            threads(i) = startThread(AddressOf work)
        Next
    End Sub

    Public Sub [stop]()
        assert(Not threads Is Nothing AndAlso threads.Length() > 0)
        For i As Int64 = 0 To threads.Length() - 1
            threads(i).Abort()
        Next
        ReDim threads(-1)
    End Sub

    Private Sub work()
        Dim handle As talkHandle = Nothing
        handle = New talkHandle()
        udpTrans.setLocalPort(port())
        Try
            While True
                If udpTrans.receive(handle.remoteAddress, handle.receive, holdtime) Then
                    Try
                        RaiseEvent receive(handle)
                    Catch ex As Exception
                        raiseError(errorHandle.errorType.exclamation,
                                   "unhandled exception caught when handling receive event, ex ", ex.Message,
                                   ", callstack ", ex.StackTrace)
                    End Try
                    If handle.send.size() > 0 Then
                        If Not udpTrans.send(handle.remoteAddress, handle.send, holdtime) Then
                            raiseError(errorHandle.errorType.exclamation,
                                       "cannot send response to ", Convert.ToString(handle.remoteAddress))
                        End If
                    End If
                Else
                    sleep(defaultWaitTime)
                End If
            End While
        Catch ex As ThreadAbortException
            udpTrans.close()
            Throw ex
        End Try
    End Sub

    Protected Overrides Sub Finalize()
        [stop]()
        MyBase.Finalize()
    End Sub

    Public Class talkHandle
        Public receive As nettransData
        Public send As nettransData
        Public remoteAddress As IPEndPoint

        Public Sub New()
            receive = New nettransData()
            send = New nettransData()
            remoteAddress = New IPEndPoint(IPAddress.Any, 0)
        End Sub
    End Class
End Class
